#ifndef __TCP_CHAT_BAR_C__
#define __TCP_CHAT_BAR_C__

#include "tcp_chat_bar.h"

// 获取新服务器网络套接字地址描述
static inline InetSockAddrDesc_st_pt getNewSvrInetSockAddrDesc (
    const char* portNumPt,    /**< 端口号指针 */
    const char* svrIPaddrPt   /**< 服务器IP地址指针 */
)
{
    // 服务器网络套接字地址描述指针
    InetSockAddrDesc_st_pt newSvrInetSockAddrDescStPt = malloc(sizeof(InetSockAddrDesc_st));

    // 初始化服务器网络套接字地址描述
    bzero(newSvrInetSockAddrDescStPt, sizeof(InetSockAddrDesc_st));
    newSvrInetSockAddrDescStPt->sin_family = AF_INET;
    newSvrInetSockAddrDescStPt->sin_port = htons(atoi(portNumPt));
    newSvrInetSockAddrDescStPt->sin_addr.s_addr = inet_addr(svrIPaddrPt);

    return newSvrInetSockAddrDescStPt;
}

// 获取新监听网络套接字地址描述
static inline InetSockAddrDesc_st_pt getNewListenInetSockAddrDesc (
    const char* portNumPt /**< 端口号指针 */
)
{
    // 新监听网络套接字地址描述指针
    InetSockAddrDesc_st_pt newListenInetSockAddrDescStPt;

    // 分配新监听网络套接字地址描述内存
    newListenInetSockAddrDescStPt = malloc(sizeof(InetSockAddrDesc_st));

    // 初始化新监听网络套接字地址描述
    bzero(newListenInetSockAddrDescStPt, sizeof(InetSockAddrDesc_st));
    newListenInetSockAddrDescStPt->sin_family = AF_INET;
    newListenInetSockAddrDescStPt->sin_port = htons(atoi(portNumPt));
    newListenInetSockAddrDescStPt->sin_addr.s_addr = htonl(INADDR_ANY);

    return newListenInetSockAddrDescStPt;
}

// 获取新超时值信息
static inline TimeValMsg_st_pt getNewListenTimeOutValMsg (
    long timeOutSecs,       /**< 超时秒数 */
    long timeOutMicroSecs   /**< 超时微秒数 */
)
{
    // 新超时值信息指针
    TimeValMsg_st_pt newTimeOutValMsgStPt;

    // 分配新超时值信息内存
    newTimeOutValMsgStPt = malloc(sizeof(TimeValMsg_st));

    // 初始化新超时值信息
    newTimeOutValMsgStPt->tv_sec = timeOutSecs;
    newTimeOutValMsgStPt->tv_usec = timeOutMicroSecs;

    return newTimeOutValMsgStPt;
}

/* ================================================================================ */

// 获取新客户端连接信息
ClientConnMsg_st_pt getNewClientConnMsg (
    const const char* portNumPt,      /**< 端口号指针 */
    const const char* svrIPaddrPt,    /**< 服务器IP地址指针 */
    int bufSize                 /**< 缓冲区大小 */                       
)
{
    // 新客户端连接信息指针
    ClientConnMsg_st_pt newclientConnMsgStPt;

    // 分配新客户端连接信息内存
    newclientConnMsgStPt = malloc(sizeof(ClientConnMsg_st));

    // 初始化新客户端连接信息
    newclientConnMsgStPt->connSockFd = socket(AF_INET, SOCK_STREAM, 0);
    newclientConnMsgStPt->inetSockAddrDescLen = sizeof(InetSockAddrDesc_st);
    newclientConnMsgStPt->svrInetSockAddrDescStPt = getNewSvrInetSockAddrDesc(portNumPt, svrIPaddrPt);
    newclientConnMsgStPt->bufSize = bufSize;
    newclientConnMsgStPt->rdBufPt = malloc(bufSize);
    newclientConnMsgStPt->wtBufPt = malloc(bufSize);

    return newclientConnMsgStPt;
}

//客户端请求连接服务器
int clientConnect2Server (
    ClientConnMsg_st_pt clientConnMsgStPt   /**< 客户端连接信息指针 */
)
{
    return connect(
        clientConnMsgStPt->connSockFd, 
        (GenSockAddrDesc_st_pt)clientConnMsgStPt->svrInetSockAddrDescStPt, 
        clientConnMsgStPt->inetSockAddrDescLen
    );
}

// 销毁客户端连接信息
void destroyClientConnMsg (
    ClientConnMsg_st_pt clientConnMsgStPt   /**< 客户端连接信息指针 */
)
{
    // 关闭连接套接字
    close(clientConnMsgStPt->connSockFd);
    // 释放服务器网络套接字地址描述内存
    free(clientConnMsgStPt->svrInetSockAddrDescStPt);
    // 释放读、写缓冲器内存
    free(clientConnMsgStPt->rdBufPt);
    free(clientConnMsgStPt->wtBufPt);
    // 释放客户端连接信息内存
    free(clientConnMsgStPt);
}

// 获取新服务器连接信息
ServerConnMsg_st_pt getNewServerConnMsg (
    const char* portNumPt,        /**< 端口号指针 */
    int bufSize,            /**< 缓冲区大小 */ 
    long timeOutSecs,       /**< 超时秒数 */
    long timeOutMicroSecs   /**< 超时微秒数 */
)
{
    // 新服务器连接信息指针
    ServerConnMsg_st_pt newServerConnMsgStPt;
    // 监听超时值信息长度
    socklen_t listenTimeOutValMsgLen;

    // 分配新服务器连接信息内存
    newServerConnMsgStPt = malloc(sizeof(ServerConnMsg_st));

    // 初始化新服务器连接信息
    newServerConnMsgStPt->lisentSockFd = socket(AF_INET, SOCK_STREAM, 0);
    newServerConnMsgStPt->connSockFd = -1;
    newServerConnMsgStPt->listenTimeOutValMsgStPt = getNewListenTimeOutValMsg(timeOutSecs, timeOutMicroSecs);
    newServerConnMsgStPt->inetSockAddrDescLen = sizeof(InetSockAddrDesc_st);
    newServerConnMsgStPt->listenInetSockAddrDescStPt = getNewListenInetSockAddrDesc(portNumPt);
    newServerConnMsgStPt->clientInetSockAddrDescStPt = NULL;
    newServerConnMsgStPt->bufSize = bufSize;
    newServerConnMsgStPt->rdBufPt = malloc(bufSize);
    newServerConnMsgStPt->wtBufPt = malloc(bufSize);
    // 初始化监听超时值信息长度
    listenTimeOutValMsgLen = sizeof(TimeValMsg_st);

    // 设置监听超时
    setsockopt(
        newServerConnMsgStPt->lisentSockFd, 
        SOL_SOCKET, SO_RCVTIMEO, 
        newServerConnMsgStPt->listenTimeOutValMsgStPt, 
        listenTimeOutValMsgLen
    );
    // 绑定监听网络套接字地址描述到监听套接字
    bind(
        newServerConnMsgStPt->lisentSockFd, 
        (GenSockAddrDesc_st_pt)newServerConnMsgStPt->listenInetSockAddrDescStPt, 
        newServerConnMsgStPt->inetSockAddrDescLen
    );
    // 设置监听
    listen(newServerConnMsgStPt->lisentSockFd, 3);

    return newServerConnMsgStPt;
}

// 销毁服务器连接信息
void destroyServerConnMsg (
    ServerConnMsg_st_pt svrConnMsgStPt  /**< 服务器连接信息指针 */
)
{
    // 关闭监听、连接套接字
    close(svrConnMsgStPt->lisentSockFd);
    close(svrConnMsgStPt->connSockFd);
    // 释放监听超时值信息内存
    free(svrConnMsgStPt->listenTimeOutValMsgStPt);
    // 释放监听网络套接字地址描述内存
    free(svrConnMsgStPt->listenInetSockAddrDescStPt);
    if (svrConnMsgStPt->clientInetSockAddrDescStPt != NULL)
    {
        // 获取了客户端网络套接字地址描述
        // 释放客户端网络套接字地址描述内存
        free(svrConnMsgStPt->clientInetSockAddrDescStPt);
    }
    // 释放读、写缓冲区内存
    free(svrConnMsgStPt->rdBufPt);
    free(svrConnMsgStPt->wtBufPt);
    // 释放服务器连接信息内存
    free(svrConnMsgStPt);
}

#endif